﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Proggy.Web.Cms.ContentModel;
using Proggy.Web.Cms.Repositories.ContentModel;
using Newtonsoft.Json;
using Proggy.Web.Cms.AppHelpers;

namespace Proggy.Web.Cms.Repositories.Published
{
    /// <summary>
    /// Published content repo
    /// </summary>
    public class PublishedContentRepository : IPublishedContentRepository
    {
        /// <summary>
        /// Constructor for internal use only
        /// </summary>
        /// <param name="contentModelRepository"></param>
        internal PublishedContentRepository(IContentModelTypeRepository contentModelRepository, IContentModelConverter converter)
        {
            // TODO: Complete member initialization
            this._contentModelRepository = contentModelRepository;
            this._converter = converter;

            // set content
            if (StartupManager.AllPublishedNodes == null)
            {
                ProggyHttpApplication.AppStartupManager.RefreshData();
            }

            this._publishedContent =
                StartupManager.AllPublishedNodes.Select(x => ContentModelConverter.ToPublishedAbstractSingle(x)).ToList().AsQueryable();
        }

        public IContentModelConverter ContentModelConverter
        {
            get { return this._converter; }
        }

        /// <summary>
        /// Published content
        /// </summary>
        [JsonIgnore]
        public IQueryable<IContentModel> PublishedContent
        {
            get
            {
                return this._publishedContent;
            }
            set
            {
                this._publishedContent = value;
            }
        }

        /// <summary>
        /// Get typed published content
        /// </summary>
        /// <typeparam name="TContentModel"></typeparam>
        /// <param name="includeSubClasses"></param>
        /// <returns></returns>
        public IQueryable<TContentModel> GetTypedPublishedContent<TContentModel>(bool includeSubClasses)
        {
            // get type
            var type = typeof(TContentModel);

            // start
            IQueryable<IContentModel> typedContentAbstract = null;

            // check
            if (includeSubClasses)
            {
                // get typed content
                typedContentAbstract =
                    this.PublishedContent
                    .Where(x =>
                        x.GetType() == type ||
                        x.GetType().IsSubclassOf(type)
                     );
            }
            else {
                // get typed content
                typedContentAbstract =
                    this.PublishedContent
                    .Where(x =>
                        x.GetType() == type
                     );
            }

            // get typed
            var typedContent = typedContentAbstract.Select(x => (TContentModel)x);

            //
            return typedContent.AsQueryable<TContentModel>();

            //return this._allContent
            //    .Where(x=>x.GetType() == typeof(TContentModel))
            //    .Select(x => (TContentModel)x).AsQueryable();
        }

        /// <summary>
        /// Get abstract content from node id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public IContentModel GetAbstractContentSingleFromId(int id)
        {
            return this.PublishedContent.SingleOrDefault(x => x.Id == id);
        }

        /// <summary>
        /// Return strongly-typed content single
        /// </summary>
        /// <typeparam name="TContentModel"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public TContentModel GetTypedContentSingleFromId<TContentModel>(int id)
        {
            return (TContentModel)this.GetAbstractContentSingleFromId(id);
        }

        /// <summary>
        /// Gets all instances of a saved property type - use sparingly as slow
        /// </summary>
        /// <typeparam name="TPropertyTypeType"></typeparam>
        /// <returns></returns>
        public IQueryable<TPropertyTypeType> GetAllPropertyValues<TPropertyTypeType>()
        {
            // start output
            var output = new List<TPropertyTypeType>();

            // iterate content
            foreach (var c in this.PublishedContent)
            {

                // get properties which match
                var propsWhichMatch = c.GetType().GetProperties().Where(x => x.PropertyType == typeof(TPropertyTypeType));

                // add
                foreach (var propWhichMatches in propsWhichMatch)
                {
                    // get value
                    var val = propWhichMatches.GetValue(c, null);

                    // check
                    if (val != null)
                    {
                        output.Add((TPropertyTypeType)val);
                    }
                }
            }

            return output.AsQueryable();
        }

        /// <summary>
        /// Returns the root node (if it exists)
        /// </summary>
        /// <returns></returns>
        public IContentModel GetRootNode()
        {
            return this.PublishedContent.SingleOrDefault(x => x.ParentId == null);
        }

        //private
        private IContentModelTypeRepository _contentModelRepository;
        IQueryable<IContentModel> _publishedContent;
        private IContentModelConverter _converter;
    }
}
